import xml.etree.ElementTree as ET
from typing import List, Dict, Union
import xml.dom.minidom
import os


def _create_change_set_element(change_set: Dict) -> tuple[ET.Element, str]:
    """
    创建一个 <changeSet> 元素
    """
    change_set_id = change_set.get("id")
    if not change_set_id:
        raise ValueError("每个 changeSet 必须包含 'id'")

    author = change_set.get("author", "test")
    context = change_set.get("context", "common")
    comment_text = change_set.get("comment", "测试数据")

    # 支持 sql 为 str 或 List[str]
    sql_input = change_set.get("sql", "")
    if isinstance(sql_input, str):
        sql_lines = [sql_input.strip()] if sql_input.strip() else []
    elif isinstance(sql_input, list):
        # 过滤空/纯空白字符串，并 strip 每行
        sql_lines = [line.strip() for line in sql_input if line and line.strip()]
    else:
        raise TypeError(
            f"sql 字段类型错误，应为 str 或 List[str]，当前为 {type(sql_input)}"
        )

    # 合并为带换行的字符串（保留用户原格式，仅确保不空行堆叠）
    sql_content = "\n".join(sql_lines)

    # 创建 changeSet 元素
    change_set_elem = ET.Element(
        "changeSet", id=change_set_id, author=author, context=context
    )

    # 添加 <comment>
    comment_elem = ET.SubElement(change_set_elem, "comment")
    comment_elem.text = comment_text

    # 添加 <sql>（仅当 sql_content 非空）
    if sql_content:
        sql_elem = ET.SubElement(change_set_elem, "sql")
        sql_elem.text = "CDATA_PLACEHOLDER"  # 占位符

    return change_set_elem, sql_content


def _generate_xml_string(root: ET.Element, sql_placeholders: List[str]) -> str:
    """
    手动处理 CDATA：替换占位符为真正的 <![CDATA[...]]>
    """
    rough_string = ET.tostring(root, encoding="unicode")
    for sql in sql_placeholders:
        cdata = f"<![CDATA[\n{sql}\n]]>"
        rough_string = rough_string.replace("CDATA_PLACEHOLDER", cdata, 1)
    return rough_string


def generate_liquibase_xml(change_sets: List[Dict], output_path: str):
    """
    生成 Liquibase 的 databaseChangeLog XML 文件。

    :param change_sets: changeSet 配置列表，每个 dict 包含：
        - id: str (必需)
        - author: str (可选，默认 "test")
        - context: str (可选，默认 "common")
        - comment: str (可选)
        - sql: str 或 List[str] (可选，空则不生成 <sql>)
    :param output_path: 输出文件路径
    """
    # 创建根元素
    root = ET.Element("databaseChangeLog")
    root.set("xmlns", "http://www.liquibase.org/xml/ns/dbchangelog")
    root.set("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
    root.set(
        "xsi:schemaLocation",
        "http://www.liquibase.org/xml/ns/dbchangelog "
        "http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd",
    )

    sql_placeholders = []

    for cs in change_sets:
        elem, sql = _create_change_set_element(cs)
        root.append(elem)
        sql_placeholders.append(sql)

    # 生成带 CDATA 的 XML 字符串
    xml_str = _generate_xml_string(root, sql_placeholders)

    # 美化格式
    try:
        parsed = xml.dom.minidom.parseString(xml_str)
        pretty_xml = parsed.toprettyxml(indent="    ")
        # 移除空行
        lines = [line for line in pretty_xml.split("\n") if line.strip()]
        pretty_xml = "\n".join(lines)
    except Exception as e:
        print(f"⚠️ XML 美化失败: {e}")
        pretty_xml = xml_str

    # 写入文件
    os.makedirs(os.path.dirname(output_path), exist_ok=True)
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(pretty_xml)

    print(f"✅ Liquibase XML 已生成：{output_path}")


if __name__ == "__main__":
    change_sets = [
        {
            "id": "1-20251104",
            "sql": """
          -- 事件明细
              INSERT INTO tf_smp_data_model (DATA_ID, DATA_MODEL_CODE, DATA_MODEL_NAME, PUB_STATE, DATA_MODEL_DESC, CREATOR, CREATE_TIME, UPDATOR, UPDATE_TIME, TENANT_ID) VALUES ('DATA9507319409406428', 'CODE6486981201526291', '事件明细', '1', '审计数据事件明细', '1148046988160331778', '2025-09-12 16:45:19', '1148046988160331778', '2025-09-12 16:45:19', -1);
              INSERT INTO tf_smp_data_model_detail (DETAIL_ID, DATA_MODEL_CODE, FIELD_NAME, FIELD_CODE, FIELD_NEED, FIELD_SHOW, FIELD_QUERY, FIELD_TYPE, TENANT_ID, SORT_VALUE) VALUES ('INFO2623057488445017', 'CODE6486981201526291', '主账号', 'user_id', '1', '1', '1', '0', -1, 0);
              INSERT INTO tf_smp_data_model_detail (DETAIL_ID, DATA_MODEL_CODE, FIELD_NAME, FIELD_CODE, FIELD_NEED, FIELD_SHOW, FIELD_QUERY, FIELD_TYPE, TENANT_ID, SORT_VALUE) VALUES ('INFO2623057488445018', 'CODE6486981201526291', '从账号', 'account_id', '1', '1', '1', '0', -1, 0);
              INSERT INTO tf_smp_data_model_detail (DETAIL_ID, DATA_MODEL_CODE, FIELD_NAME, FIELD_CODE, FIELD_NEED, FIELD_SHOW, FIELD_QUERY, FIELD_TYPE, TENANT_ID, SORT_VALUE) VALUES ('INFO2623057488445019', 'CODE6486981201526291', '源IP', 'event_srcip', '1', '1', '1', '0', -1, 0);
              INSERT INTO tf_smp_data_model_detail (DETAIL_ID, DATA_MODEL_CODE, FIELD_NAME, FIELD_CODE, FIELD_NEED, FIELD_SHOW, FIELD_QUERY, FIELD_TYPE, TENANT_ID, SORT_VALUE) VALUES ('INFO2623057488445020', 'CODE6486981201526291', '目的IP', 'event_destip', '1', '1', '1', '0', -1, 0);
              INSERT INTO tf_smp_data_model_detail (DETAIL_ID, DATA_MODEL_CODE, FIELD_NAME, FIELD_CODE, FIELD_NEED, FIELD_SHOW, FIELD_QUERY, FIELD_TYPE, TENANT_ID, SORT_VALUE) VALUES ('INFO2623057488445021', 'CODE6486981201526291', '操作', 'operator', '1', '1', '1', '0', -1, 0);
              INSERT INTO tf_smp_data_model_detail (DETAIL_ID, DATA_MODEL_CODE, FIELD_NAME, FIELD_CODE, FIELD_NEED, FIELD_SHOW, FIELD_QUERY, FIELD_TYPE, TENANT_ID, SORT_VALUE) VALUES ('INFO2623057488445022', 'CODE6486981201526291', '产生时间', 'event_time', '1', '1', '1', '0', -1, 0);
          """,
        },
        {
            "id": "2-20251105",
            "author": "dev_zhang",
            "context": "fj",
            "comment": "补充事件字段：目的IP、操作、产生时间",
            "sql": [
                "INSERT INTO tf_smp_data_model_detail (DETAIL_ID, DATA_MODEL_CODE, FIELD_NAME, FIELD_CODE, FIELD_NEED, FIELD_SHOW, FIELD_QUERY, FIELD_TYPE, TENANT_ID, SORT_VALUE) VALUES ('INFO2623057488445020', 'CODE6486981201526291', '目的IP', 'event_destip', '1', '1', '1', '0', -1, 0);",
                "INSERT INTO tf_smp_data_model_detail (DETAIL_ID, DATA_MODEL_CODE, FIELD_NAME, FIELD_CODE, FIELD_NEED, FIELD_SHOW, FIELD_QUERY, FIELD_TYPE, TENANT_ID, SORT_VALUE) VALUES ('INFO2623057488445021', 'CODE6486981201526291', '操作', 'operator', '1', '1', '1', '0', -1, 0);",
                "INSERT INTO tf_smp_data_model_detail (DETAIL_ID, DATA_MODEL_CODE, FIELD_NAME, FIELD_CODE, FIELD_NEED, FIELD_SHOW, FIELD_QUERY, FIELD_TYPE, TENANT_ID, SORT_VALUE) VALUES ('INFO2623057488445022', 'CODE6486981201526291', '产生时间', 'event_time', '1', '1', '1', '0', -1, 0);",
            ],
        },
    ]

    generate_liquibase_xml(change_sets, "output/changelog.xml")
